package com.huaxin.dss2.data.bean.properties;

import static com.huaxin.dss2.util.BeanUtil.castValue;
import static com.huaxin.dss2.util.BeanUtil.checkBasicType;


import com.huaxin.dss2.data.bean.DefaultValueEntry;
import com.huaxin.dss2.data.bean.annotation.Default;
import com.huaxin.dss2.data.bean.annotation.Properties;
import com.huaxin.dss2.util.PropertiesUtil;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import javax.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import sun.rmi.runtime.Log;

/**
 * @author : luqing
 * @date : 2018/12/13 17:08
 */
@Component
@Slf4j
public class PropertiesPersister implements ApplicationContextAware {

    private ApplicationContext applicationContext;


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @PostConstruct
    public void init() {

        Map<String, Object> beanMap = applicationContext.getBeansWithAnnotation(Properties.class);
        PropertiesTrie trie = new PropertiesTrie();
        beanMap.forEach((String key, Object value) -> {
            String pre = value.getClass().getAnnotation(Properties.class).pre();
            System.out.println(PropertiesUtil.getPreProperty(pre));
            Map<String, String> preProperty = PropertiesUtil.getPreProperty(pre);
            preProperty.forEach(trie::insert);
            trie.copyProperties(pre, value);
            bindingDefaultValue(value);
        });
    }


    private void bindingDefaultValue(Object value){
        LinkedBlockingQueue<DefaultValueEntry> queue = new LinkedBlockingQueue<>();
        for (Field field : value.getClass().getDeclaredFields()) {
            queue.add(new DefaultValueEntry(field,value));
        }
        while (!queue.isEmpty()){
            DefaultValueEntry poll = queue.poll();
            Field field = poll.getField();
            Object object = poll.getValue();
            Default defaultValue = poll.getField().getAnnotation(Default.class);
            if (defaultValue!=null){
                try {
                    PropertyDescriptor pd = new PropertyDescriptor(field.getName(),object.getClass());
                    Object invoke = pd.getReadMethod().invoke(object);
                    if (StringUtils.isEmpty(invoke)){
                        pd.getWriteMethod().invoke(object,castValue(defaultValue.value(),field.getType()));
                        continue;
                    }
                } catch (IntrospectionException | IllegalAccessException | InvocationTargetException e) {
                    log.error("初始化默认值出错",poll.getField().getName(),poll.getValue());
                }
            }

            if (!checkBasicType(field.getType())){
                for (Field field1 : field.getType().getDeclaredFields()) {
                    try {
                        PropertyDescriptor pd = new PropertyDescriptor(field.getName(),object.getClass());
                        Object invoke = pd.getReadMethod().invoke(object);
                        queue.add(new DefaultValueEntry(field1,invoke));
                    } catch (IntrospectionException | IllegalAccessException | InvocationTargetException e) {
                        log.error("初始化默认值出错",poll.getField().getName(),poll.getValue());
                    }
                }
            }
        }
    }




}
